﻿using System.IO;
using System;
using System.Threading;

namespace Library.Network {
  public abstract class MessageHandler {
    //private bool _callingStop;
    public ServerListener Server { get; internal set; }

    public virtual void StopReceive() {
      //if (_callingStop) return;
      //_callingStop = true;
      CloseHandler();
    }

    //protected ClientConnectedHash ClientConnectedHash {
    //get { return Server.ClientConnectedHash; }
    //}

    internal void DoReceive() {
      try {
        while (true) {
          string messageType = BaseMessage.ReadAsciiString(Client.ClientSocket.GetStream());
          if (String.IsNullOrEmpty(messageType)) break;
          var continueLoop = ProcessMessage(messageType);
          if (!continueLoop) break;
        }
      } catch (IOException) {
        FireClientDisconnectedEvent();
      } catch (InvalidOperationException) {
        FireClientDisconnectedEvent();
      } catch (ThreadAbortException) {
        FireClientDisconnectedEvent();
      } finally {
        try {
          StopReceive();
          // ReSharper disable EmptyGeneralCatchClause
        } catch {
          // ReSharper restore EmptyGeneralCatchClause
        }
      }
    }

    public Connector Client;
    protected abstract bool ProcessMessage(string messageType);
    protected void ReceiveMessage(IMessage message) {
      message.Receive(Client.ClientSocket);
    }

    protected void SendMessage(IMessage message) {
      message.Send(Client.ClientSocket);
    }

    private readonly object _synFireEventObject = new object();
    private bool _firedEvent;
    protected void FireClientDisconnectedEvent() {
      if (_firedEvent) return;
      lock (_synFireEventObject) {
        if (_firedEvent) return;
        _firedEvent = true;

      }
      Server.InvokeClientDiconnected(new ClientDisconnectedEventArgs { Client = Client });
    }

    private void CloseHandler() {
      try {
        Client.ClientSocket.GetStream().Close(0);
        //if (fireClientDisconnectedEvent) {
        FireClientDisconnectedEvent();
        //}
        // ReSharper disable EmptyGeneralCatchClause
      } catch {
        // ReSharper restore EmptyGeneralCatchClause
      }
    }
  }
}
